/*
 *
 * Copyright (C) 2012 Walter Lütgenau
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * 
 *      http://www.apache.org/licenses/LICENSE-2.0
 * 
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 * 
 */
package offset.nodes.server.html.model;

import java.io.ByteArrayInputStream;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.LinkedList;
import java.util.List;
import javax.jcr.Node;
import javax.jcr.RepositoryException;
import javax.jcr.Session;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import offset.nodes.Constants;
import offset.nodes.server.binary.controller.BinaryAttribute;
import offset.nodes.server.model.RepositoryModel;
import offset.nodes.server.servlet.book.component.ComponentBook;
import offset.nodes.server.servlet.book.content.BookPageType;
import offset.nodes.server.servlet.book.content.Page;
import offset.nodes.server.servlet.book.provider.PageProvider;
import offset.nodes.server.view.FacesUtils;

/**
 *
 * @author Walter Luetgenau
 */
public class PageModel extends RepositoryModel {

    /** Creates a new instance of PageModel */
    public PageModel(Session session) {
        super(session);
    }

    public void removeNode(String uuid) throws RepositoryException {
        if (uuid == null)
            return;
        Node node = getSession().getNodeByUUID(uuid);
        node.remove();
        getSession().save();
    }

    public String getString(String filename) throws IOException {
        InputStream in = new FileInputStream(filename);
        byte[] buf = new byte[in.available()];
        in.read(buf);
        in.close();
        return new String(buf);
    }

    protected boolean isHtmlDiv(Node node) throws RepositoryException {
        if (node.isNodeType(Constants.TYPE_HTML_DIV))
            return true;
        if (node.isNodeType(Constants.NT_FROZEN_NODE))
            if (node.getProperty(Constants.JCR_FROZEN_PRIMARY_TYPE).getString().equals(Constants.TYPE_HTML_DIV))
                return true;

        return false;
    }

    public BinaryAttribute getDownloadInfo(Node node) throws RepositoryException {
        if (node == null)
            return null;

        if (!isHtmlDiv(node))
            return super.getDownloadInfo(node);

        BinaryAttribute info = new BinaryAttribute();
        if (node.hasProperty(Constants.PROP_MODIFICATION_TIMESTAMP))
            info.setModification(node.getProperty(Constants.PROP_MODIFICATION_TIMESTAMP).getDate().getTime());
        info.setName(node.getName());

        String contentType = null;
        if (node.hasProperty(Constants.PROP_MIME_TYPE))
            contentType = node.getProperty(Constants.PROP_MIME_TYPE).getValue().getString();

        if (!node.hasProperty(Constants.PROP_DATA))
            return null;

        StringBuilder buf = new StringBuilder();
        buf.append("<div>");
        buf.append(node.getProperty(Constants.PROP_DATA).getValue().getString());
        buf.append("</div>");
        InputStream input = new ByteArrayInputStream(buf.toString().getBytes());

        info.setInput(input);
        info.setContentType(contentType);
        return info;
    }

    /**
     * Return the css file path of all css files, that are children of the nodes
     * provided in path, except for the leaf node.
     *
     * @param path
     * @return the paths as a string array
     * @throws RepositoryException
     */
    public List<String> getCSSInPath(String path) throws RepositoryException {
        Node[] cssFilesInPath = CSSFinder.getInstance().findPathConfigurators(path);
        List<String> cssFiles = new LinkedList<String>();
        for (Node cssFileInPath : cssFilesInPath) {
            cssFiles.add(cssFileInPath.getPath());
        }
        return cssFiles;
    }

    /**
     * Return the javascript file path of all javascript files, that are children of the nodes
     * provided in path, except for the leaf node.
     *
     * @param path
     * @return the paths as a string array
     * @throws RepositoryException
     */
    public List<String> getJavascriptInPath(String path) throws RepositoryException {
        Node[] jsFilesInPath = JavascriptFinder.getInstance().findPathConfigurators(path);
        List<String> jsFiles = new LinkedList<String>();
        for (Node jsFileInPath : jsFilesInPath) {
            jsFiles.add(jsFileInPath.getPath());
        }
        return jsFiles;
    }
    
    /**
     * Return the page content of the referenced page.
     *
     * The page content is the element, that has id "content".
     *
     * @param reference the UUID referencing the page
     * @param context the HttpContext needed to retrieve and filter the page
     * @return the page content
     * @throws ServletException
     * @throws IOException
     * @throws Exception
     */
    public String getPageContent(String reference, HttpContext context) throws ServletException, IOException, Exception {
        PageProvider pageProvider = new PageProvider(context.getServlet(), 
                new EmptyParametersHttpRequestWrapper(context.getRequest(), new String[] {Constants.PAR_DATA_REFERENCE, Constants.PAR_MODE}),
                context.getResponse());
        String htmlReference = Constants.QUERY_SEPARATOR + Constants.PAR_DATA_REFERENCE + Constants.QUERY_ASSIGNEMENT_OPERATOR + reference
                + Constants.QUERY_PARAMETER_SEPARATOR + Constants.PAR_MODE + Constants.QUERY_ASSIGNEMENT_OPERATOR + Constants.PARVALUE_PRINT;
        String content = new String(pageProvider.getResourceByUrl(htmlReference).getContent());
        Page page = new Page(new ComponentBook(), 0, htmlReference, content, null, true, BookPageType.inTree);
        return extractElementContentByTag("body", page.getContent().getString());
    }

    /**
     * Extract the content of the element provided from the xml.
     *
     * @param element the element tag
     * @param xml the xml content
     * @return the content of the element
     */
    protected String extractElementContentByTag(String element, String xml) {
        int startPos = xml.indexOf("<" + element);
        int endPos = xml.indexOf("</" + element);

        if (startPos < 0 || endPos < 0)
            return xml;

        return xml.substring(startPos + element.length() + 2, endPos);
    }
    
    /**
     * Return a hyperlink for the node referenced by uuid.
     * 
     * @param uuid the uuid
     * @return the hyperlink
     * @throws RepositoryException a repository exception
     */
    public String getRepositoryHyperlink(HttpServletRequest request, String uuid) throws RepositoryException {
        String result;
        
        Node node = getReferencedNode(uuid);
        if (node == null)
            result = createRepositoryHyperlink(request, uuid, uuid);
        else
            result = createRepositoryHyperlink(request, node.getName(), uuid);
        
        return result;
    }
    
    /**
     * Create a repository hyperlink using name and uuid.
     * 
     * @param name the name
     * @param uuid the uuid
     * @return the hyperlink
     */
    protected String createRepositoryHyperlink(HttpServletRequest request, String name, String uuid) {
        return "<a n-binary=\"true\" href=\"" + FacesUtils.getRepositoryPath(request) + "?reference=" + uuid + "\">" + name + "</a>";
    }
    

}
